package com.vivi.codereview.tools;

import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class SelectRangeHandler {

	/**
	 * To check if we have a valid range selection entry (1;5-7;3 for example)
	 */
	private static final String SELECT_RANGE_REGEXP = getCOMBINED_RANGE_INDEX_REGEXP();

	/**
	 * Example of select range
	 */
	private static final String SELECT_RANGE_EXAMPLE = "1;3-5;2";

	/**
	 * Example of select range, in exploded mode
	 */
	private static final String SELECT_RANGE_EXAMPLE_EXPLODED = "1, 2, 3, 4, 5";

	/**
	 * token for a range selection in select range
	 */
	private static final String SELECT_RANGE_RANGE = "-";

	/**
	 * token for a split between for selection in a select range
	 */
	private static final String SELECT_RANGE_SEPARATOR = ";";

	/**
	 * token to select everything in a select range - regular expression mode
	 */
	private static final String SELECT_RANGE_JOKER_ALL_REGEXP = "\\*";

	/**
	 * token to select everything in a select range - string mode
	 */
	private static final String SELECT_RANGE_JOKER_ALL = "*";

	/**
	 * Token in case you don't want to add any file into the zip
	 */
	private static final String SELECT_RANGE_NOTHING = "";

	public boolean isNullSelectRange(String select) {
		return SELECT_RANGE_NOTHING.equalsIgnoreCase(select);
	}

	public boolean isAllSelectRange(String select) {
		return SELECT_RANGE_JOKER_ALL.equalsIgnoreCase(select);
	}

	public String getSelectRangeExample() {
		return SELECT_RANGE_EXAMPLE;
	}

	public String getSelectRangeAllToken() {
		return SELECT_RANGE_JOKER_ALL;
	}

	/**
	 * Display select range help
	 *
	 * @return
	 */
	public String getSelectFilesDisplayedText() throws Exception {
		return "Please select files you want to use in list above.\n'" + SELECT_RANGE_EXAMPLE
		        + "' for example to have " + SELECT_RANGE_EXAMPLE_EXPLODED + "\n'" + SELECT_RANGE_JOKER_ALL
		        + "' for all\n<Enter> for nothing:";
	}

	/**
	 * Check if is a valid select range input.
	 *
	 * @param input
	 * @return
	 */
	public boolean isValidForSelectRange(String input) throws Exception {
		boolean isValid = input.matches(SELECT_RANGE_REGEXP);
		Log.log("is " + input + " a valid select range? " + isValid, Log.D);
		return isValid;
	}

	/**
	 * <pre>
	 * Since we can enter many items, we support many ways to define the items to be selected:
	 * a;b;c;d -> to select independently many items
	 * a-c -> to select a range from a to b
	 * </pre>
	 *
	 * @param input
	 * @return
	 */
	public Set<Integer> fromSelectRangeToExplodedSelection(String input) throws Exception {
		Set<Integer> output = new TreeSet<Integer>();
		StringTokenizer strToken = new StringTokenizer(input, SELECT_RANGE_SEPARATOR);
		while (strToken.hasMoreTokens()) {
			String token = strToken.nextToken();
			if (token.contains(SELECT_RANGE_RANGE)) {
				// In the case we have a range
				try {
					Integer from = Integer.parseInt(token.substring(0, token.indexOf(SELECT_RANGE_RANGE)));
					Integer to = Integer.parseInt(token.substring(token.indexOf(SELECT_RANGE_RANGE)
					        + SELECT_RANGE_RANGE.length()));
					if (from < to) {
						for (int i = from; i <= to; i++) {
							output.add(i);
						}
					} else {
						Log.log("Why are you trying to get from " + from + " to " + to + "?!", Log.W);
					}
				} catch (NumberFormatException nfe) {
					Log.log("Man, this is not a range " + token, Log.W);
				}
			} else {
				try {
					output.add(Integer.parseInt(token));
				} catch (NumberFormatException nfe) {
					Log.log(token + "is not a valid int number, try again.", Log.W);
				}
			}
		}
		Log.log("Exploded mode for this select range " + input + " is " + output.toString(), Log.D);
		return output;
	}

	/**
	 * Generate the Pattern to check the rate range entry
	 *
	 * @return
	 */
	private static String getCOMBINED_RANGE_INDEX_REGEXP() {
		// A number with at least one digit
		final String digit = "\\d+";
		// We can add only one '-' and another digit, not mandatory
		final String range = digit + "(" + SELECT_RANGE_RANGE + digit + ")?";
		// We can have one are many range, not mandatory
		final String separator = range + "(" + SELECT_RANGE_SEPARATOR + range + ")*";
		// We can have this joker
		final String joker = SELECT_RANGE_JOKER_ALL_REGEXP;
		// We can have either the joker, either a full list, and nothing else
		return "^((" + separator + ")|(" + joker + "))$";
	}

	public String getMessageWrongSelectRange() {
		return "is not valid. Only '" + SELECT_RANGE_JOKER_ALL + "', '" + SELECT_RANGE_NOTHING + "', or '"
		        + SELECT_RANGE_EXAMPLE + "' format";
	}

}
